
package com.gcloud.mesh.alert.timer;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.gcloud.mesh.alert.proxy.AlarmProxy;
import com.gcloud.mesh.alert.proxy.IAlarmProxy;
import com.gcloud.mesh.alert.redis.AlarmRedis;
import com.gcloud.mesh.alert.service.HandleService;
import com.gcloud.mesh.alert.service.HistoryService;
import com.gcloud.mesh.alert.service.NotifyTemplateService;
import com.gcloud.mesh.alert.service.PolicyLinkmanService;
import com.gcloud.mesh.alert.service.PolicyService;
import com.gcloud.mesh.alert.service.RuleService;
import com.gcloud.mesh.asset.service.IAssetService;
import com.gcloud.mesh.asset.service.ICloudResourceService;
import com.gcloud.mesh.dcs.service.AppService;
import com.gcloud.mesh.header.enums.AlertHistoryStatus;
import com.gcloud.mesh.header.enums.MonitorMeter;
import com.gcloud.mesh.header.msg.monitor.StatisticsMsg;
import com.gcloud.mesh.header.vo.alert.HistoryVo;
import com.gcloud.mesh.header.vo.alert.LinkmanVo;
import com.gcloud.mesh.header.vo.alert.NotifyTemplateVo;
import com.gcloud.mesh.header.vo.alert.PolicyVo;
import com.gcloud.mesh.header.vo.alert.RuleVo;
import com.gcloud.mesh.header.vo.asset.CloudResourceItemVo;
import com.gcloud.mesh.header.vo.asset.DeviceItemVo;
import com.gcloud.mesh.header.vo.dcs.AppVo;
import com.gcloud.mesh.header.vo.monitor.StatisticsPointVo;
import com.gcloud.mesh.header.vo.monitor.StatisticsResourceVo;
import com.gcloud.mesh.header.vo.monitor.StatisticsVo;
import com.gcloud.mesh.monitor.service.StatisticsCheatService;
import com.gcloud.mesh.monitor.service.StatisticsService;
import com.gcloud.mesh.monitor.util.CompareUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class AlertTimer {

	// private static Logger LOG = LoggerFactory.getLogger(AlertTimer.class);

	@Autowired
	StatisticsService statisticsService;

	@Autowired
	StatisticsCheatService statisticsCheatService;

	@Autowired
	RuleService alarmRuleService;

	@Autowired
	HistoryService alarmHistoryService;

	@Autowired
	NotifyTemplateService templateService;

	@Autowired
	PolicyService alarmPolicyService;

	@Autowired
	PolicyLinkmanService alarmPolicyLinkmanService;

	@Autowired
	AlarmRedis alarmRedis;

	@Autowired
	IAssetService assetService;

	@Autowired
	ICloudResourceService cloudResourceService;

	@Autowired
	AppService appService;

	@Autowired
	private HandleService alarmHandleService;

	private static final SimpleDateFormat monitorSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Scheduled(fixedDelay = 1000 * 60)
	public void process() {
		log.info("check alarm start");
		Boolean needToRefresh = null;
		// 去掉秒数，整分钟
		// long currentTime = System.currentTimeMillis() / 1000;
		// currentTime = (currentTime - currentTime % 60) * 1000;

		long currentTime = System.currentTimeMillis();
		Date endDate = new Date(currentTime);
		List<HistoryVo> alarms = new ArrayList<HistoryVo>();
		Date duration_beginDate = null;
		// 获取策略
		List<PolicyVo> defaultPolicys = this.alarmPolicyService.list();
		try {
			for (PolicyVo policy : defaultPolicys) {
				if (!policy.getEnable()) {
					continue;
				}

				Date nowTime = new Date();
				int second = nowTime.getHours() * 3600 + nowTime.getMinutes() * 60;
				// if (policy.getEnableStartTime() > second || second >
				// policy.getEnableEndTime()) {
				// LOG.info("policy " + policy.getId() + " " + second + " not in
				// enable time["
				// + policy.getEnableStartTime() + "," +
				// policy.getEnableEndTime() + "]");
				// continue;
				// }

				log.info("check policy：" + policy.getId());
				for (RuleVo rule : this.alarmRuleService.getAlarmRules("policyId", policy.getId())) {
					if (!rule.getEnabled()) {
						continue;
					}

					List<String> resourceIds = alarmRedis.getKeys(rule.getMeter());
					for (String resourceId : resourceIds) {

						try {
							duration_beginDate = new Date(currentTime - rule.getDuration() * 1000);
							String startTime = monitorSdf.format(duration_beginDate);
							String endTime = monitorSdf.format(new Date(currentTime));

							StatisticsMsg msg = new StatisticsMsg();
							msg.setResourceId(resourceId);
							msg.setDcId(policy.getRegionId());
							msg.setBeginTime(startTime);
							msg.setEndTime(endTime);
							msg.setMeter(rule.getMeter());
							StatisticsVo statisticsVo = statisticsCheatService.statistics(msg);
							for (StatisticsResourceVo statisticsResources : statisticsVo.getList()) {
								StatisticsPointVo statistics = statisticsResources.getPoints().get(0);
								if (statistics.getValue() != null) {
									Double statisticsValue = statistics.getValue() / 1d;
									String statisticsInstance = statisticsResources.getInstance();

									if (CompareUtil.compare(statisticsValue, rule.getThreshold(),
											rule.getComparisonOperator())) {

										Map<String, String> params = new HashMap<>();
										params.put("resourceName", statisticsResources.getResourceId());

										// 转换id
										MonitorMeter meter = MonitorMeter.getByMeter(rule.getMeter());
										String meterType = meter.getType();
										if (meterType.equals("服务器") || meterType.equals("交换机")
												|| meterType.equals("UPS") || meterType.equals("空调")
												|| meterType.equals("配电箱")) {
											DeviceItemVo device = assetService
													.detailDevice(statisticsResources.getResourceId(), "");
											if (device != null) {
												params.put("resourceName", device.getName());
												statisticsResources.setResourceName(device.getName());
											} else {
												break;
											}
										} else if (meterType.equals("虚拟机") || meterType.equals("容器")) {
											CloudResourceItemVo vm = cloudResourceService
													.detail(statisticsResources.getResourceId());
											if (vm != null) {
												params.put("resourceName", vm.getName());
												statisticsResources.setResourceName(vm.getName());
											} else {
												break;
											}
										} else if (meterType.equals("应用") || meterType.equals("迁移代价")) {
											AppVo app = appService.checkAndGet(statisticsResources.getResourceId());
											if (app != null) {
												params.put("resourceName", app.getName());
												statisticsResources.setResourceName(app.getName());
											} else {
												break;
											}
										} else {
											// statisticsResources.setResourceName(resourceId);
											break;
										}

										DecimalFormat df = new DecimalFormat("0.00");

										params.put("threshold", df.format(rule.getThreshold()).toString());
										params.put("value", df.format(statisticsValue).toString());
										params.put("resourceInstance", statisticsResources.getInstance());
										params.put("unit", rule.getUnit());
										params.put("comparisonOperator",
												getComparisonOperatorString(rule.getComparisonOperator()));
										String unit = rule.getUnit();
										if (StringUtils.isBlank(params.get("unit"))) {
											if (StringUtils.isBlank(unit)) {
												unit = "";
											}
											params.put("unit", unit);
										}
										// try to save

										HistoryVo alarmHistoryVo = new HistoryVo();
										IAlarmProxy alarmProxy = AlarmProxy
												.getAlarmProxyByResourceType(rule.getResourceType());

										// 给告警历史的tag赋值
										alarmProxy.setAlarmHistory4ImportData(alarmHistoryVo, statisticsResources);

										// 给告警模板参数赋值
										alarmProxy.setTemplatesParams(params, statisticsResources);

										NotifyTemplateVo template = this.templateService
												.getNotifyTemplate(rule.getMeter(), params);

										alarmHistoryVo.setCreateTime(new Date());
										alarmHistoryVo.setAlertTime(new Date(currentTime));
										// alarmHistoryVo.setContent(template.getContent());
										alarmHistoryVo.setContent(template.getContent());
										alarmHistoryVo.setMeter(rule.getMeter());
										alarmHistoryVo.setResourceType(rule.getResourceType());
										alarmHistoryVo.setTitle(template.getTitle());
										alarmHistoryVo.setLevel(rule.getLevel());

										// 告警次数统计
										Integer alarmCountCache = alarmRedis.get(rule.getId(), alarmHistoryVo,
												statisticsInstance);
										if (alarmCountCache == null) {
											alarmCountCache = 0;
										}
										alarmRedis.set(rule.getId(), ++alarmCountCache, alarmHistoryVo,
												statisticsInstance);
										alarmHistoryVo.setNotifyCount(alarmCountCache);

										HistoryVo cache = alarmRedis.get(rule.getId(), alarmHistoryVo.getMeter(),
												alarmHistoryVo.getResourceId(), alarmHistoryVo.getHost(),
												alarmHistoryVo.getPlatformType(), alarmHistoryVo.getRegionId(),
												statisticsInstance, null);
										if (cache != null) {
											break;
										}

										alarms.add(alarmHistoryVo);

										// 规则等级在1及以下不发送
										// if (policy.getNotifyEnable() &&
										// rule.getLevel() > 1) {
										if (policy.getNotifyEnable()) {
											// gcloud_monitor_alarm_ruleId_{0}_meter_{1}_recourceId_{2}_host_{3}_instance_{4}
											HistoryVo alarmHistoryCache = alarmRedis.get(rule.getId(),
													alarmHistoryVo.getMeter(), alarmHistoryVo.getResourceId(),
													alarmHistoryVo.getHost(), alarmHistoryVo.getPlatformType(),
													alarmHistoryVo.getRegionId(), statisticsInstance, null);
											log.info("Alarm notify: " + alarmHistoryVo.toString());
											List<LinkmanVo> linkmanVos = alarmPolicyLinkmanService
													.getByPolicyId(policy.getId());
											try {

												alarmHistoryVo.setStatus(AlertHistoryStatus.SEND_ALARM.getValue());

												log.info("policyId：" + policy.getId() + "发送邮件：" + template.getTitle());
												alarmHandleService.sendMessage(template.getTitle(),
														template.getContent());
											} catch (Exception e) {
												alarmHistoryVo.setStatus(AlertHistoryStatus.NOTIFY_FAILED.getValue());
												log.error("failed to publish notification: ", e);
											}

										}
									} else {
										// 告警恢复
										HistoryVo alarmHistoryCache = null;
										alarmHistoryCache = alarmRedis.get(rule.getId(), rule.getMeter(),
												statisticsResources.getResourceId(), statisticsResources.getHost(),
												policy.getPlatform(), policy.getRegionId(), statisticsInstance, null);
										if (alarmHistoryCache != null && !alarmHistoryCache.isRecover()) {
											log.info("Alarm recover: " + alarmHistoryCache.toString());
											alarmHistoryCache.setRecover(true);
											// 弃用recover,改成恢复后就remove掉告警的key
											alarmRedis.update(rule.getId(), alarmHistoryCache, statisticsInstance,
													(long) policy.getChannelSilence());
											alarmRedis.remove(rule.getId(), alarmHistoryCache, statisticsInstance,
													(long) policy.getChannelSilence());
											alarmRedis.remove(rule.getId(), alarmHistoryCache, statisticsInstance);

											if (policy.getNotifyEnable() && rule.getLevel() > 1) {
												Map<String, String> params = new HashMap<>();
												params.put("resourceName", statisticsResources.getResourceId());
												params.put("threshold", rule.getThreshold().toString());
												params.put("value", statisticsValue.toString());
												params.put("resourceInstance", statisticsResources.getInstance());
												params.put("comparisonOperator",
														getComparisonOperatorString(rule.getComparisonOperator()));
												params.put("unit", rule.getUnit());

												// 给恢复告警模板的参数赋值
												IAlarmProxy alarmProxy = AlarmProxy
														.getAlarmProxyByResourceType(rule.getResourceType());
												alarmProxy.setRecoverTemplatesParams(params, statisticsResources);

												List<LinkmanVo> linkmanVos = alarmPolicyLinkmanService
														.getByPolicyId(policy.getId());
												NotifyTemplateVo template = this.templateService
														.getRecoverTemplate(rule.getMeter(), params);
												try {

													alarmHandleService.sendMessage(template.getTitle(),
															template.getContent());
												} catch (Exception e) {
													log.error("failed to publish notification: ", e);
												}
											}
										}
									}

								}
							}
						} catch (Exception e) {
							log.error("", e);
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("", e);
			e.printStackTrace();
		}
		if (alarms.size() > 0) {
			alarmHandleService.handleAlarms(alarms);
		}

		log.info("check alarm end");
	}

	private String getComparisonOperatorString(Integer comparisonOperator) {
		switch (comparisonOperator) {
		case 0:
			return ">=";
		case 1:
			return "> ";
		case 2:
			return "<= ";
		case 3:
			return "< ";
		case 4:
			return "== ";
		case 5:
			return "!= ";
		default:
			return "!= ";
		}
	}

}
